package cn.nfwx.tv.down.execute;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.annotation.IntRange;

import com.hdl.m3u8.utils.MUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import cn.nfwx.tv.db.AppDatabase;
import cn.nfwx.tv.db.DownProgramDao;
import cn.nfwx.tv.db.DownProgramModel;
import cn.nfwx.tv.db.TsDao;
import cn.nfwx.tv.db.TsProgramModel;
import cn.nfwx.tv.down.DownloadConstant;
import cn.nfwx.tv.down.DownloadStatus;
import cn.nfwx.tv.down.bean.DownloadInfo;
import cn.nfwx.tv.down.utils.LogUtils;
import cn.nfwx.tv.helper.NetworkHelper;

/**
 * Todo 这个地方可以改用 FutureTask来做
 */
public class DownloadTask implements Runnable {

    public static final String TAG = "DownloadTask";

    private Context context;
    private DownloadInfo info;
    private boolean isPause;
    private DownProgramModel downProgram;

    public DownloadTask(final Context context, final DownloadInfo info) {
        this.context = context;
        this.info = info;
        DownProgramDao downProgramDao = AppDatabase.getInstance(context).programDao();

        //初始化下载文件信息
        List<DownProgramModel> downProgramModels = downProgramDao.queryAllByUrl(info.getM3u8Url());

        if (!downProgramModels.isEmpty()) {
            downProgram = downProgramModels.get(0);
            downProgram.setDownloadStatus(DownloadStatus.DEFAULT);
            downProgram.setStats(DownProgramModel.STATS_WAIT);
            sendBroadcast();
        } else {
            downProgram = downProgramModels.get(0);
            downProgram.setDownloadStatus(DownloadStatus.FAIL);
            downProgram.setStats(DownProgramModel.STATS_FAIL);
            sendBroadcast();
        }
    }

    private void sendBroadcast() {
        Intent intent = new Intent();
        intent.setAction(info.getAction());
        Bundle bundle = new Bundle();
        bundle.putParcelable(DownloadConstant.EXTRA_INTENT_DOWNLOAD, downProgram);
        intent.putExtras(bundle);
        context.sendBroadcast(intent);
    }

    @Override
    public void run() {
        downProgram.setDownloadStatus(DownloadStatus.PREPARE);
        LogUtils.i(TAG, "准备开始下载");

        sendBroadcast();

        int i = (downProgram.getDownloadLocation() <= 0 ? 0 : downProgram.getDownloadLocation() - 1);
        long millis = SystemClock.uptimeMillis();
        DownProgramDao downProgramDao = AppDatabase.getInstance(context).programDao();
        TsDao tsDao = AppDatabase.getInstance(context).tsDao();
        List<TsProgramModel> tsProgramModels = tsDao.getTsFromProgram(downProgram.getId());
        if (tsProgramModels != null) {
            while (i < tsProgramModels.size()) {
                TsProgramModel tsProgramModel = tsProgramModels.get(i);
                int result = 0;
                if (tsProgramModel.getStats() == TsProgramModel.STATS_NO
                        || tsProgramModel.getStats() == TsProgramModel.STATS_DOWNING) {
                    result = download(tsProgramModel);
                } else if (tsProgramModel.getStats() == TsProgramModel.STATS_SUCCESS) {
                    i++;
                    continue;
                }

                if (result == 0) {
                    i++;
                    if (isPause) {
                        LogUtils.i(TAG, "下载过程 设置了 暂停");
                        downProgram.setDownloadStatus(DownloadStatus.PAUSE);
                        downProgram.setStats(DownProgramModel.STATS_PAUSE);
                        isPause = false;
                        downProgram.setDownloadLocation(i);
                        downProgram.setDownloadLocationTs(tsProgramModel.getTsUrl());
                        downProgramDao.update(downProgram);
                        sendBroadcast();
                        return;
                    } else {
                        if (SystemClock.uptimeMillis() - millis >= 1000) {
                            millis = SystemClock.uptimeMillis();
                            downProgram.setDownloadStatus(DownloadStatus.LOADING);
                            downProgram.setDownloadLocation(i);
                            downProgram.setStats(DownProgramModel.STATS_DOWNLOADING);
                            downProgram.setDownloadLocationTs(tsProgramModel.getTsUrl());
                            downProgramDao.update(downProgram);
                            sendBroadcast();
                        }
                    }
                } else if (result == -1) { // 异常退出
                    downProgram.setDownloadStatus(DownloadStatus.FAIL);
                    sendBroadcast();
                    return;
                } else if (result == 1) { //ts无法获取，跳过直接获取下一个
                    i++;
                    if (SystemClock.uptimeMillis() - millis >= 1000) {
                        millis = SystemClock.uptimeMillis();
                        downProgram.setDownloadStatus(DownloadStatus.LOADING);
                        downProgram.setDownloadLocation(i);
                        downProgram.setStats(DownProgramModel.STATS_DOWNLOADING);
                        downProgram.setDownloadLocationTs(tsProgramModel.getTsUrl());
                        downProgramDao.update(downProgram);
                        sendBroadcast();
                    }
                } else if (result == 2) { // 无网络暂停
                    downProgram.setDownloadStatus(DownloadStatus.PAUSE);
                    downProgram.setStats(DownProgramModel.STATS_PAUSE);
                    downProgramDao.update(downProgram);
                    sendBroadcast();
                    return;
                }
            }

            List<String> tsLoadPaths = new ArrayList<>();
            for (TsProgramModel tsProgramModel : tsProgramModels) {
                tsLoadPaths.add(tsProgramModel.getLocalPath());
            }
            MUtils.mergePath(tsLoadPaths, downProgram.getLocalPath());//合并ts
            downProgram.setDownloadStatus(DownloadStatus.COMPLETE);
            downProgram.setStats(DownProgramModel.STATS_SUCCESS);
            downProgramDao.update(downProgram);
            sendBroadcast();
        } else {
            downProgramDao.delete(downProgram);
        }
    }


    public void pause() {
        downProgram.setStats(DownProgramModel.STATS_PAUSE);
        downProgram.setDownloadStatus(DownloadStatus.PAUSE);
        sendBroadcast();
        isPause = true;
        if (AppDatabase.getInstance(context).isOpen()) {
            AppDatabase.getInstance(context).programDao().update(downProgram);
        }
    }

    public void start() {
        downProgram.setStats(DownProgramModel.STATS_WAIT);
        sendBroadcast();
        isPause = false;
        if (AppDatabase.getInstance(context).isOpen()) {
            AppDatabase.getInstance(context).programDao().update(downProgram);
        }
    }

    @IntRange(from = DownloadStatus.WAIT, to = DownloadStatus.FAIL)
    public int getStatus() {
        if (null != downProgram) {
            return downProgram.getDownloadStatus();
        }
        return DownloadStatus.FAIL;
    }

    public void setFileStatus(@IntRange(from = DownloadStatus.WAIT, to = DownloadStatus.FAIL)
                                      int status) {
        downProgram.setDownloadStatus(status);
    }

    public void sendBroadcast(Intent intent) {
        context.sendBroadcast(intent);
    }

    public DownloadInfo getDownLoadInfo() {
        return info;
    }

    public DownProgramModel getDownProgram() {
        return downProgram;
    }

    private int download(TsProgramModel tsProgramModel) {
        TsDao tsDao = AppDatabase.getInstance(context).tsDao();
        FileOutputStream fos = null;
        HttpURLConnection http = null;
        InputStream inStream = null;
        try {
            URL sizeUrl = new URL(tsProgramModel.getTsUrl());
            HttpURLConnection sizeHttp = (HttpURLConnection) sizeUrl.openConnection();
            sizeHttp.setRequestMethod("GET");
            sizeHttp.connect();
            long totalSize = sizeHttp.getContentLength();
            sizeHttp.disconnect();

            if (totalSize <= 0) {
                File file = new File(tsProgramModel.getLocalPath());
                if (file.exists()) {
                    file.delete();
                }
                LogUtils.e(TAG, "文件大小 = " + totalSize + "\t, 终止下载过程");
                return -1;
            }

            URL url = new URL(tsProgramModel.getTsUrl());
            http = (HttpURLConnection) url.openConnection();
            http.setConnectTimeout(60000);
            http.setRequestProperty("Connection", "Keep-Alive");
            http.setReadTimeout(60000);
            http.connect();
            int responeCode = http.getResponseCode();
            if (responeCode == 200) {
                inStream = http.getInputStream();
                byte[] buffer = new byte[1024 * 2];
                int offset;

                File tsFile = new File(tsProgramModel.getLocalPath());
                if (tsFile.exists()) {
                    if (tsFile.length() == totalSize) {
                        tsProgramModel.setStats(TsProgramModel.STATS_SUCCESS);
                        tsDao.update(tsProgramModel);
                        return 0;
                    } else {
                        tsFile.delete();
                    }
                }
                tsFile.createNewFile();

                fos = new FileOutputStream(tsFile);

                tsProgramModel.setStats(TsProgramModel.STATS_DOWNING);
                tsDao.update(tsProgramModel);

                while ((offset = inStream.read(buffer)) != -1) {
                    fos.write(buffer, 0, offset);
                }

                tsProgramModel.setStats(TsProgramModel.STATS_SUCCESS);
                tsDao.update(tsProgramModel);
                return 0;
            } else {
                if (NetworkHelper.getInstance().hasConnection(context)) {
                    tsProgramModel.setStats(TsProgramModel.STATS_FAIL);
                    tsDao.update(tsProgramModel);
                    return 1;
                } else {
                    tsProgramModel.setStats(TsProgramModel.STATS_NO_NETWORK);
                    tsDao.update(tsProgramModel);
                    return 2;
                }
            }
        } catch (Exception e) {
            LogUtils.e(TAG, "下载过程发生失败");
            e.printStackTrace();
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
                if (inStream != null) {
                    inStream.close();
                }
                if (http != null) {
                    http.disconnect();
                }
            } catch (IOException e) {
                LogUtils.e(TAG, "finally 块  关闭文件过程中 发生异常");
                e.printStackTrace();
            }
        }
        File file = new File(tsProgramModel.getLocalPath());
        if (file.exists()) {
            file.delete();
        }
        return -1;
    }
}
